﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;


namespace DBS_semka_2
{
    class cFileManipulation
    {
        #region premenne
        private string psFileName;
        private int piNumberOfBlocks = 0;

        public int iNumberOfBlocks
        {
            get { return piNumberOfBlocks; }
            set { piNumberOfBlocks = value; }
        }

        private int piRecordLength;

        private int piNumberOfRecordPerBlock = 10;

        ArrayList paUnusedBlocks = new ArrayList();

        public int iNumberOfRecordPerBlock
        {
            get { return piNumberOfRecordPerBlock; }
            set { piNumberOfRecordPerBlock = value; }
        }

        public string sFileName
        {
            get { return psFileName; }
            set { psFileName = value; }
        }

        private int piKeyLength;

        private int piLengthOfHeader = sizeof(long) + sizeof(bool) + 2 * sizeof(int);

        public int iLengthOfHeader
        {
            get { return piLengthOfHeader; }
            set { piLengthOfHeader = value; }
        }

               
        [NonSerialized] 
        private FileStream rFile; 
        #endregion


        public cFileManipulation(string pa_sFileName, int pa_iNumberOfRecords, int pa_iRecordLength, int pa_iKeyLength)
        {
            psFileName = pa_sFileName;
            piNumberOfRecordPerBlock = pa_iNumberOfRecords;
            piKeyLength = pa_iKeyLength;
            piRecordLength = pa_iRecordLength;
            if (pa_sFileName != "")
            {
                if(!File.Exists(pa_sFileName))
                {
                    try
                    {
                        rFile = System.IO.File.Create(pa_sFileName);
                    }
                    catch (Exception ex)
                    {
                        throw (new Exception("Problem pri vytvarani suboru"));
                    }
                    finally
                    {
                        rFile.Close();
                    }
                }
            }
            else
            {
                throw new Exception("Nazov suboru nesmie byt prazdny");
            }
        }
        /// <summary>
        /// Otvori subor
        /// </summary>
        private void openFile()
        {
            if(File.Exists(psFileName))
            {
                try
                {
                    rFile = File.Open(psFileName, FileMode.Open);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    closeFile();
                    openFile();
                }
            }
            else
            {
                throw(new Exception("Subor sa nepodarilo otvorit"));
            }
        }

        private void closeFile()
        {
            rFile.Close();
        }

        public long createNewBlock()
        {
            if (paUnusedBlocks.Count == 0)
            {
                openFile();
                rFile.Seek(0, SeekOrigin.End);
                long iPosition = rFile.Position;
                BinaryWriter rWriter = new BinaryWriter(rFile);
                rWriter.Write((new cBlock(piKeyLength, piNumberOfRecordPerBlock,iPosition)).toByteArray());
                piNumberOfBlocks++;
                closeFile();
                return iPosition;
            }
            else
            {
                long iPosition = (long)paUnusedBlocks[paUnusedBlocks.Count-1];
                paUnusedBlocks.RemoveAt(paUnusedBlocks.Count - 1);
                openFile();
                rFile.Seek(iPosition, SeekOrigin.Begin);
                BinaryWriter rWriter = new BinaryWriter(rFile);
                rWriter.Write((new cBlock(piKeyLength, piNumberOfRecordPerBlock, iPosition)).toByteArray());
                closeFile();
                return iPosition;
            }
        }

        public void cleanBlock(long pa_iPosition)
        {
            openFile();
            rFile.Seek(pa_iPosition, SeekOrigin.Begin);
            BinaryWriter rWriter = new BinaryWriter(rFile);
            cBlock oToWrite = new cBlock(piKeyLength, piNumberOfRecordPerBlock, pa_iPosition);
            oToWrite.bUsed = false;
            rWriter.Write(oToWrite.toByteArray());
            closeFile();
            paUnusedBlocks.Add(pa_iPosition);
        }

        /// <summary>
        /// Vpise do bloku
        /// </summary>
        /// <param name="pa_iPostion">Pozicia, na ktoru sa vklada</param>
        /// <param name="pa_aValues">Hodnoty, ktore sa vkladaju</param>
        public void writeBlock(long pa_iPostion, byte[] pa_aValues)
        {
            openFile();
            rFile.Seek(pa_iPostion, SeekOrigin.Begin);
            BinaryWriter rWriter = new BinaryWriter(rFile);
            rWriter.Write(pa_aValues);
            closeFile();
        }
         
        /// <summary>
        /// Nacita cely blok 
        /// </summary>
        /// <param name="pa_iPosition"></param>
        /// <returns></returns>
        public byte[] readBlock(long pa_iPosition)
        {
            openFile();
            rFile.Seek(pa_iPosition, SeekOrigin.Begin);
            BinaryReader rReader = new BinaryReader(rFile);
            byte[] oValues = rReader.ReadBytes(piLengthOfHeader + piNumberOfRecordPerBlock * piRecordLength);
            closeFile();
            return oValues;
            
        }
    }
}


